package com.gxd.commons.utils;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Maps;
import com.gxd.commons.codec.DigestsUtils;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.*;
import java.util.*;

public class HttpUtils {
    private static Logger log = LoggerFactory.getLogger(HttpUtils.class);

    private static MultiThreadedHttpConnectionManager connectionManager = null;
    private static int connectionTimeOut = 200000;
    private static int socketTimeOut = 200000;
    private static int maxConnectionPerHost = 500;
    private static int maxTotalConnections = 10000;
    private static HttpClient client;
    static {
        connectionManager = new MultiThreadedHttpConnectionManager();
        connectionManager.getParams().setConnectionTimeout(connectionTimeOut);
        connectionManager.getParams().setSoTimeout(socketTimeOut);
        connectionManager.getParams().setDefaultMaxConnectionsPerHost(maxConnectionPerHost);
        connectionManager.getParams().setMaxTotalConnections(maxTotalConnections);
        client = new HttpClient(connectionManager);

//        client = new HttpClient();
//        HttpConnectionManagerParams params = client.getHttpConnectionManager().getParams();
//        params.setConnectionTimeout(connectionTimeOut);
//        params.setSoTimeout(socketTimeOut);
    }

    /**
     * 发起https请求并获取结果
     *
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式（GET、POST）
     * @param paramMap 提交的数据
     * @return
     */
    public static String httpRequest(String requestUrl, String requestMethod, Map<String,String> paramMap) {

        log.debug("请求URL: {}", requestUrl);
        log.debug("请求方式: {}", requestMethod);
        log.debug("提交数据: {}", FastJsonUtils.toJSONString(paramMap));

        StringBuffer buffer = new StringBuffer();
        try {
//            // 创建SSLContext对象，并使用我们指定的信任管理器初始化
//            TrustManager[] tm = { new MyX509TrustManager() };
//            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
//            sslContext.init(null, tm, new java.security.SecureRandom());
//            // 从上述SSLContext对象中得到SSLSocketFactory对象
//            SSLSocketFactory ssf = sslContext.getSocketFactory();

            URL url = new URL(requestUrl);
            HttpURLConnection httpUrlConn = (HttpURLConnection) url.openConnection();
//            httpUrlConn.setSSLSocketFactory(ssf);

            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);
            // 设置请求方式（GET/POST）
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod)) {
                httpUrlConn.connect();
            }
            // 当有数据需要提交时
            if (null != paramMap) {
                StringBuffer paramStr = new StringBuffer();
                for (Map.Entry<String, String> entry : paramMap.entrySet()) {

                    paramStr.append(entry.getKey());
                    paramStr.append("=");
                    paramStr.append(entry.getValue());
                    paramStr.append("&");
                }


                OutputStream outputStream = httpUrlConn.getOutputStream();
                // 注意编码格式，防止中文乱码
                outputStream.write(paramStr.toString().getBytes("UTF-8"));
                outputStream.close();
            }

            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);

            String str = null;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            inputStream = null;
            httpUrlConn.disconnect();
        } catch (ConnectException ce) {
            log.error("服务器连接超时");
        } catch (Exception e) {
            log.error("服务器请求报错:{}", e);
        }
        String result = buffer.toString();
        log.debug("服务器响应数据: " + result);
        return result;
    }

    public static String get(String url, Map<String, String> paramMap) throws Exception {

        String requestParam = "";
        if(paramMap != null) {
            Iterator e = paramMap.entrySet().iterator();
            while(e.hasNext()) {
                Map.Entry entry = (Map.Entry)e.next();
                requestParam += (String)entry.getKey();
                requestParam += "=";
                //requestParam += URLEncoder.encode((String)entry.getValue(), "GBK");
                requestParam += (String)entry.getValue();
                requestParam += "&";
            }
        }
        String getUrl = url + "?" + requestParam.substring(0,requestParam.length()-1);
        HttpMethod method = new GetMethod(getUrl);

        String responseBodyAsString = null;
        try {
            if(log.isDebugEnabled()) {
                log.debug("\n\n\n%%%%%%%%%%%%%%%http send: " + getUrl + "\n%%%%%%%%%%%%%%%");
            }
            int statusCode = client.executeMethod(method);
            if(statusCode == 200) {
                responseBodyAsString = method.getResponseBodyAsString();
            } else {
                responseBodyAsString = method.getResponseBodyAsString();
            }

            if(log.isDebugEnabled()) {
                log.debug("\n%%%%%%%%%%%%%%%http state: " + statusCode + "\n%%%%%%%%%%%%%%%response:" + responseBodyAsString);
            }
        } catch (Exception var10) {
            log.error("http request exception   %%%%% http url:" + getUrl);
            log.error(var10.getMessage(), var10);
            throw var10;
        } finally {
            if(method != null) {
                method.releaseConnection();
                method = null;
            }
        }

        return responseBodyAsString;
    }

    /**
     * 根据手机号获取手机号信息
     * @param servialNumber
     * @return
     * @throws MalformedURLException
     */
    public static JSONObject getMobileInfo(String servialNumber) throws MalformedURLException{
        String jsonString = null;
        JSONArray array = null;
        JSONObject jsonObject = null;
        String urlString = "?tel=" + servialNumber;
        StringBuffer sb = new StringBuffer();
        BufferedReader buffer;
        URL url = new URL(urlString);
        try{
            InputStream in = url.openStream();

            // 解决乱码问题
            buffer = new BufferedReader(new InputStreamReader(in,"gb2312"));
            String line = null;
            while((line = buffer.readLine()) != null){
                sb.append(line);
            }
            in.close();
            buffer.close();
            // System.out.println(sb.toString());
            jsonString = sb.toString();
            // 替换掉“__GetZoneResult_ = ”，让它能转换为JSONArray对象
            jsonString = jsonString.replaceAll("^[__]\\w{14}+[_ = ]+", "[");
            // System.out.println(jsonString+"]");
            String jsonString2 = jsonString + "]";
            // 把STRING转化为json对象
            array = JSONArray.parseArray(jsonString2);
            // 获取JSONArray的JSONObject对象，便于读取array里的键值对
            jsonObject = array.getJSONObject(0);

        }catch(Exception e){
            log.error("异常信息：", e.getMessage());
        }
        return jsonObject;
    }

    /**
     * 参数加密
     * @param param
     * @param appSecret
     * @return
     * @throws Exception
     */
    public static String sign(Map<String, String> param, String appSecret) throws Exception {

        param.remove("sign");

        Object[] keys = param.keySet().toArray();
        Arrays.sort(keys);
        StringBuffer paramStr = new StringBuffer();
        for (Object key : keys) {
            String value = (String) param.get(key);
            if (value!=null && !"".equals(value)) {
                paramStr.append(key).append(value);
            }
        }
        paramStr.append(appSecret);
        return DigestsUtils.MD5Encode(paramStr.toString());
    }

    /**http下载*/
    public static boolean httpDownload(String httpUrl,String saveFile){
        // 下载网络文件
        int bytesum = 0;
        int byteread = 0;

        URL url = null;
        try {
            url = new URL(httpUrl);

            URLConnection conn = url.openConnection();
            InputStream inStream = conn.getInputStream();
            FileOutputStream fs = new FileOutputStream(saveFile);

            byte[] buffer = new byte[1204];
            while ((byteread = inStream.read(buffer)) != -1) {
                bytesum += byteread;
                fs.write(buffer, 0, byteread);
            }
            log.debug("下载文件总大小: {}", bytesum);
            fs.close();
            return true;
        } catch (FileNotFoundException e) {
            log.error("异常信息：", e.getMessage());
            return false;
        } catch (IOException e) {
            log.error("异常信息：", e.getMessage());
            return false;
        }
    }
    /**
     * 使用 Map按key进行排序得到key=value的字符串
     *
     * @param map
     * @param equalsType K与V之间的拼接字符串 = 或者其他...
     * @param spliceType K-V与K-V之间的拼接字符串  & 或者|...
     * @return
     */
    public static String getParamsString(Map<String, Object> map, String equalsType,
                                         String spliceType) {
        if (map == null || map.isEmpty()) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            if (sb.length() == 0) {
                sb.append(entry.getKey()).append(equalsType).append(entry.getValue());
            } else {
                sb.append(spliceType).append(entry.getKey()).append(equalsType)
                        .append(entry.getValue());
            }
        }
        return sb.toString();
    }

    /**
     * 基于HttpClient 3.1的通用POST方法
     *
     * @param url       提交的URL
     * @param paramsMap 提交<参数，值>Map
     * @return 提交响应
     */
    public static String post(String url, Map<String, String> paramsMap) {
        HttpClient client = new HttpClient();
        try {
            PostMethod method = new PostMethod(url);
            if (paramsMap != null) {
                NameValuePair[] namePairs = new NameValuePair[paramsMap.size()];
                int i = 0;
                for (Map.Entry<String, String> param : paramsMap.entrySet()) {
                    NameValuePair pair = new NameValuePair(param.getKey(), param.getValue());
                    namePairs[i++] = pair;
                }
                method.setRequestBody(namePairs);
                HttpMethodParams param = method.getParams();
                param.setContentCharset("UTF-8");
            }
            client.executeMethod(method);
            return method.getResponseBodyAsString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 返回值类型为Map<String, Object>
     *
     * @param request
     * @return
     */
    public static Map<String, Object> getParameterMap(HttpServletRequest request) {
        //把请求参数封装到Map<String, String[]>中
        Map<String, String[]> properties = request.getParameterMap();
        Map<String, Object> returnMap = new HashMap<>();
        Iterator<Map.Entry<String, String[]>> iter = properties.entrySet().iterator();
        String name = "";
        String value = "";
        while (iter.hasNext()) {
            Map.Entry<String, String[]> entry = iter.next();
            name = entry.getKey();
            Object valueObj = entry.getValue();
            if (null == valueObj) {
                value = "";
            } else if (valueObj instanceof String[]) {
                String[] values = (String[]) valueObj;
                for (int i = 0; i < values.length; i++) { //用于请求参数中有多个相同名称
                    value = values[i] + ",";
                }
                value = value.substring(0, value.length() - 1);
            } else {
                value = valueObj.toString();//用于请求参数中请求参数名唯一
            }
            returnMap.put(name, value);
        }
        return returnMap;
    }

    public static String getParamsString2(Map<String, String[]> map, String equalsType, String spliceType) {
        if (map != null && !map.isEmpty()) {
            StringBuilder sb = new StringBuilder();
            Iterator var4 = map.entrySet().iterator();

            while(var4.hasNext()) {
                Map.Entry<String, String[]> entry = (Map.Entry)var4.next();
                for(String value : entry.getValue()){
                    if (sb.length() == 0) {
                        sb.append(entry.getKey()).append(equalsType).append(value);
                    } else {
                        sb.append(spliceType).append(entry.getKey()).append(equalsType).append(value);
                    }
                }
            }

            return sb.toString();
        } else {
            return null;
        }
    }
    /**
     * 返回值类型为Map<String, String>
     *
     * @param request
     * @return
     */
    public static Map<String, String> getParameters(HttpServletRequest request) {
        Map<String, String[]> properties = request.getParameterMap();//把请求参数封装到Map<String, String[]>中
        Map<String, String> returnMap = new HashMap<String, String>();
        String name = "";
        String value = "";
        for (Map.Entry<String, String[]> entry : properties.entrySet()) {
            name = entry.getKey();
            String[] values = entry.getValue();
            if (null == values) {
                value = "";
            } else if (values.length > 1) {
                for (int i = 0; i < values.length; i++) { //用于请求参数中有多个相同名称
                    value = values[i] + ",";
                }
                value = value.substring(0, value.length() - 1);
            } else {
                value = values[0];//用于请求参数中请求参数名唯一
            }
            returnMap.put(name, value);
        }
        return returnMap;
    }

    /**
     * 解析出url请求的路径，包括页面
     * @param strURL url地址
     * @return url路径
     */
    public static String UrlPage(String strURL) {
        String strPage=null;
        String[] arrSplit=null;

        strURL=strURL.trim().toLowerCase();

        arrSplit=strURL.split("[?]");
        if(strURL.length()>0)
        {
            if(arrSplit.length>1)
            {
                if(arrSplit[0]!=null)
                {
                    strPage=arrSplit[0];
                }
            }
        }

        return strPage;
    }
    /**
     * 去掉url中的路径，留下请求参数部分
     * @param strURL url地址
     * @return url请求参数部分
     */
    private static String TruncateUrlPage(String strURL) {
        String strAllParam=null;
        String[] arrSplit=null;

        strURL=strURL.trim().toLowerCase();

        arrSplit=strURL.split("[?]");
        if(strURL.length()>1)
        {
            if(arrSplit.length>1)
            {
                if(arrSplit[1]!=null)
                {
                    strAllParam=arrSplit[1];
                }
            }
        }

        return strAllParam;
    }

    public static Map<String, String> requestParam2Map(HttpServletRequest request) {
        Map map = Maps.newHashMap();
        Enumeration paramNames = request.getParameterNames();
        while (paramNames.hasMoreElements()) {
            String paramName = (String) paramNames.nextElement();

            String[] paramValues = request.getParameterValues(paramName);
            if (paramValues.length == 1) {
                String paramValue = paramValues[0];
                if (paramValue.length() != 0) {
                    log.debug("参数：" + paramName + "=" + paramValue);
                    map.put(paramName, paramValue);
                }
            }
        }
        return map;
    }
    /**
     * 解析出url参数中的键值对
     * 如 "index.jsp?Action=del&id=123"，解析出Action:del,id:123存入map中
     * @param URL  url地址
     * @return  url请求参数部分
     */
    public static Map<String, String> URLRequest(String URL) {
        Map<String, String> mapRequest = new HashMap<String, String>();

        String[] arrSplit=null;

        String strUrlParam=TruncateUrlPage(URL);
        if(strUrlParam==null)
        {
            return mapRequest;
        }
        //每个键值为一组 www.2cto.com
        arrSplit=strUrlParam.split("[&]");
        for(String strSplit:arrSplit)
        {
            String[] arrSplitEqual=null;
            arrSplitEqual= strSplit.split("[=]");

            //解析出键值
            if(arrSplitEqual.length>1)
            {
                //正确解析
                mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);

            }
            else
            {
                if(arrSplitEqual[0]!="")
                {
                    //只有参数没有值，不加入
                    mapRequest.put(arrSplitEqual[0], "");
                }
            }
        }
        return mapRequest;
    }
    public static Map<String, String> ParamURLRequest(String paramURL) {
        Map<String, String> mapRequest = new HashMap<String, String>();

        String[] arrSplit=null;
        //每个键值为一组
        arrSplit=paramURL.split("[&]");
        for(String strSplit:arrSplit) {
            String[] arrSplitEqual=null;
            arrSplitEqual= strSplit.split("[=]");
            //解析出键值
            if(arrSplitEqual.length>1)
            {
                //正确解析
                mapRequest.put(arrSplitEqual[0], arrSplitEqual[1]);
            }
            else
            {
                if(arrSplitEqual[0]!="")
                {
                    //只有参数没有值，不加入
                    mapRequest.put(arrSplitEqual[0], "");
                }
            }
        }
        return mapRequest;
    }
}
